package com.zlc.platform.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zlc.common.annotation.Parameter;
import com.zlc.common.annotation.SyncResourceConstant;
import com.zlc.common.annotation.SysRedisConstant;
import com.zlc.common.annotation.SysRedisKeyConstant;
import com.zlc.common.common.constant.SysControlType;
import com.zlc.common.common.entity.PageVo;
import com.zlc.common.common.service.ContextHolder;
import com.zlc.common.core.sys.mapper.MayanSysControlMapper;
import com.zlc.common.core.sys.model.entity.MayanSysNotification;
import com.zlc.common.core.sys.model.vo.MayanSysControlVo;
import com.zlc.common.core.user.mapper.MayanPlatUserMapper;
import com.zlc.common.model.control.OnlineRequest;
import com.zlc.common.model.user.UserInfo;
import com.zlc.common.util.*;
import com.zlc.platform.model.OnlineEntity;
import com.zlc.platform.model.cache.CacheKey;
import com.zlc.platform.model.cache.CacheSystemEntity;
import com.zlc.platform.model.control.AdminControlEntity;
import com.zlc.platform.model.control.SysCache;
import com.zlc.platform.model.control.SysCpu;
import com.zlc.platform.model.control.SysThread;
import com.zlc.platform.service.ControlService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.DataType;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import reactor.core.publisher.Flux;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

import static com.zlc.common.common.constant.PlatformRedisConstant.MAYAN_PLATFORM_LOGIN_CACHE;
import static com.zlc.common.common.constant.PlatformRedisConstant.MAYAN_PLATFORM_LOGIN_USER;


/**
 * 系统监控
 */
@Slf4j
@Service
public class ControlServiceImpl implements ControlService {

    @Autowired
    private MayanPlatUserMapper mayanPlatUserMapper;

    @Autowired
    private MayanSysControlMapper mayanSysControlMapper;
    @Autowired
    private FluxUtil fluxUtil;

    @Override
    public PageVo<OnlineEntity> queryOnlineUserList(OnlineRequest request) {
        List<OnlineEntity> allLoginUser = getAllLoginUser();
        if(!ObjectUtils.isEmpty(request.getLoginUsername())){
            allLoginUser = allLoginUser.stream().filter(entity -> entity.getUsername().contains(request.getLoginUsername())).collect(Collectors.toList());
        }
        int pageNumber = request.getPageNum() - 1;
        int pageSize = request.getPageSize();
        //代码分页
        List<OnlineEntity> result = allLoginUser.subList(Math.min(((pageNumber) * pageSize), allLoginUser.size()),
                Math.min((pageNumber + 1) * pageSize, allLoginUser.size()));
        return PageVo.page(result, allLoginUser.size());
    }

    private List<OnlineEntity> getAllLoginUser(){
        Set<Object> tokens = RedisUtils.setGet(MAYAN_PLATFORM_LOGIN_CACHE);
        if(ObjectUtils.isEmpty(tokens)){
            return new ArrayList<>();
        }
        Set<String> keys = new HashSet<>();
        tokens.forEach(token->{
            keys.add(MAYAN_PLATFORM_LOGIN_USER + token);
        });
        List<Object> valueList = RedisUtils.multiGet(keys);
        if(ObjectUtils.isEmpty(valueList)){
            return new ArrayList<>();
        }
        List<OnlineEntity> entities = new ArrayList<>();

        for(Object value : valueList){
            if(ObjectUtils.isEmpty(value)){
                continue;
            }
            UserInfo info = JsonHelper.jsonToObject(String.valueOf(value),UserInfo.class);
            OnlineEntity entity = JsonHelper.coverObject(info.getUser(),OnlineEntity.class);
            entity.setLoginTime(info.getLoginTime());
            Integer betweenHourNumber = DateUtils.getBetweenHourNumber(info.getLoginTime(), new Date());
            entity.setOnlineHour(betweenHourNumber == 0 ? 1 : betweenHourNumber);
            entities.add(entity);
        }
        return entities;
    }

    @Override
    public AdminControlEntity queryAdminControlEntity() {
        AdminControlEntity entity = new AdminControlEntity();
        //查询最新的系统监控
        MayanSysControlVo nowCache = mayanSysControlMapper.queryNew(SysControlType.SYS_CACHE.getControlType());
        MayanSysControlVo nowThread = mayanSysControlMapper.queryNew(SysControlType.SYS_THREAD.getControlType());
        MayanSysControlVo nowCpu = mayanSysControlMapper.queryNew(SysControlType.SYS_CPU.getControlType());
        entity.setCache(JsonHelper.jsonToObject(nowCache.getControlContent(),SysCache.class));
        entity.setThread(JsonHelper.jsonToObject(nowThread.getControlContent(), SysThread.class));
        entity.setCpu(JsonHelper.jsonToObject(nowCpu.getControlContent(), SysCpu.class));

        List<MayanSysControlVo> controlVos = mayanSysControlMapper.queryAllControl();
        //内存监控
        List<MayanSysControlVo> cacheList = controlVos.stream().filter(c -> SysControlType.SYS_CACHE.getControlType().equals(c.getControlType()))
                .sorted(Comparator.comparing(MayanSysControlVo::getCreateTime).reversed()).collect(Collectors.toList());
        entity.setCacheList(cacheList.stream().map(c -> {
            SysCache sysCache = JsonHelper.jsonToObject(c.getControlContent(), SysCache.class);
            sysCache.setTime(DateUtils.format(c.getCreateTime(),"HH:mm"));
            return sysCache;
        }).sorted(Comparator.comparing(SysCache::getTime)).collect(Collectors.toList()));
        //线程监控
        List<MayanSysControlVo> threadList = controlVos.stream().filter(c -> SysControlType.SYS_THREAD.getControlType().equals(c.getControlType()))
                .sorted(Comparator.comparing(MayanSysControlVo::getCreateTime).reversed()).collect(Collectors.toList());
        entity.setThreadList(threadList.stream().map(c ->{
            SysThread sysThread = JsonHelper.jsonToObject(c.getControlContent(), SysThread.class);
            sysThread.setTime(DateUtils.format(c.getCreateTime(),"HH:mm"));
            return sysThread;
        }).sorted(Comparator.comparing(SysThread::getTime)).collect(Collectors.toList()));
        //CPU监控
        List<MayanSysControlVo> cpuList = controlVos.stream().filter(c -> SysControlType.SYS_CPU.getControlType().equals(c.getControlType()))
                .sorted(Comparator.comparing(MayanSysControlVo::getCreateTime).reversed()).collect(Collectors.toList());
        entity.setCpuList(cpuList.stream().map(c ->{
            SysCpu sysCpu = JsonHelper.jsonToObject(c.getControlContent(), SysCpu.class);
            sysCpu.setTime(DateUtils.format(c.getCreateTime(),"HH:mm"));
            return sysCpu;
        }).sorted(Comparator.comparing(SysCpu::getTime)).collect(Collectors.toList()));
        return entity;
    }

    @Override
    public Flux<String> getAdminControl() {
        return fluxUtil.createSSE(()->{
            AdminControlEntity entity = queryAdminControlEntity();
            return JsonHelper.toJson(entity);
        },()->"推送消息失败");
    }

    @Override
    public List<CacheSystemEntity> queryCacheSystemList() {
        List<CacheSystemEntity> entities = new ArrayList<>();
        Map<String, Object> beans = SpringContextUtils.getApplicationContext().getBeansWithAnnotation(SysRedisConstant.class);
        for (Object systemBean : beans.values()) {
            SysRedisConstant systemAnn = systemBean.getClass().getAnnotation(SysRedisConstant.class);
            CacheSystemEntity entity = new CacheSystemEntity();
            entity.setSystemCode(systemAnn.systemCode());
            entity.setSystemName(systemAnn.systemName());
            List<CacheKey> cacheKeys = new ArrayList<>();
            Field[] fields = systemBean.getClass().getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                SysRedisKeyConstant annotation = field.getAnnotation(SysRedisKeyConstant.class);
                if (annotation != null) {
                    CacheKey cacheKey = new CacheKey();
                    cacheKey.setDesc(annotation.desc());
                    try {
                        cacheKey.setKey(String.valueOf(field.get(systemBean)));
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                    cacheKeys.add(cacheKey);
                }
            }
            entity.setCacheKey(cacheKeys);
            entities.add(entity);
        }
        return entities;
    }

    @Override
    public Set<String> queryRedisKeys(String prefixKey) {
        return RedisUtils.keys(prefixKey);
    }

    @Override
    public String getRedisValue(String redisKey) {
        DataType type = RedisUtils.getType(redisKey);
        if(type == DataType.STRING){
            return RedisUtils.get(redisKey);
        }else if (type == DataType.HASH){
            return JsonHelper.toJson(RedisUtils.hashOperate().values(redisKey));
        }else if (type == DataType.LIST){
            return JsonHelper.toJson(RedisUtils.listOperate().range(redisKey,0,-1));
        }else if (type == DataType.SET){
            return JsonHelper.toJson(RedisUtils.setOperate().members(redisKey));
        }else if (type == DataType.ZSET){
            return JsonHelper.toJson(RedisUtils.zSetOperate().range(redisKey,0,-1));
        }
        return RedisUtils.get(redisKey);
    }
}
